package org.sws.trigger.http;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.web.bind.annotation.*;
import org.sws.domain.activity.model.entity.*;
import org.sws.domain.activity.model.valobj.OrderTradeTypeVO;
import org.sws.domain.activity.service.armory.IActivityArmory;
import org.sws.domain.activity.service.partake.IActivityPartakeService;
import org.sws.domain.activity.service.product.IRaffleActivitySkuProductService;
import org.sws.domain.activity.service.quota.IRaffleActivityAccountQuotaService;
import org.sws.domain.award.model.entity.AwardRecordEntity;
import org.sws.domain.award.model.valobj.AwardStateVO;
import org.sws.domain.award.service.IAwardService;
import org.sws.domain.behavior.model.entity.BehaviorEntity;
import org.sws.domain.behavior.model.valobj.BehaviorTypeVO;
import org.sws.domain.behavior.service.IBehaviorRebateService;
import org.sws.domain.credit.model.entity.CreditAccountEntity;
import org.sws.domain.credit.model.entity.TradeEntity;
import org.sws.domain.credit.model.valobj.TradeNameVO;
import org.sws.domain.credit.model.valobj.TradeTypeVO;
import org.sws.domain.credit.service.ICreditAdjustService;
import org.sws.domain.strategy.model.entity.RaffleAwardEntity;
import org.sws.domain.strategy.model.entity.RaffleFactorEntity;
import org.sws.domain.strategy.service.IRaffleStrategy;
import org.sws.domain.strategy.service.armory.IStrategyArmory;
import org.sws.trigger.api.IRaffleActivityService;
import org.sws.trigger.dto.*;
import org.sws.types.annotations.DCCValue;
import org.sws.types.annotations.RateLimiterAccessInterceptor;
import org.sws.types.common.page.PageResult;
import org.sws.types.enums.ResponseCode;
import org.sws.types.exception.AppException;
import org.sws.types.model.Response;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @Author sws
 * @Date 2025/3/25 09:21
 * @description: 抽奖活动http接口
 */
@Slf4j
@RestController
@CrossOrigin("${app.config.cross-origin}")
@RequestMapping("/api/bigmarket/raffle/activity/")
@DubboService(version = "1.0.0")
public class RaffleActivityController implements IRaffleActivityService {
    private final SimpleDateFormat dateFormatDay = new SimpleDateFormat("yyyyMMdd");

    @Resource
    private IStrategyArmory strategyArmory;
    @Resource
    private IActivityArmory activityArmory;
    @Resource
    private IActivityPartakeService activityPartakeService;
    @Resource
    private IRaffleStrategy raffleStrategy;
    @Resource
    private IAwardService awardService;
    @Resource
    private IBehaviorRebateService behaviorRebateService;
    @Resource
    private IRaffleActivityAccountQuotaService raffleActivityAccountQuotaService;
    @Resource
    private IRaffleActivitySkuProductService raffleActivitySkuProductService;
    @Resource
    private ICreditAdjustService creditAdjustService;

    @DCCValue("degradeSwitch:close")
    private String degradeSwitch;

    @GetMapping("armory")
    @Override
    public Response<Boolean> armory(@RequestParam Long activityId) {
        try {
            log.info("活动装配，数据预热，开始 activityId:{}", activityId);
            // 1. 活动装配
            activityArmory.assembleActivitySkuByActivityId(activityId);
            // 2. 策略装配
            strategyArmory.assembleLotteryStrategyByActivityId(activityId);
            Response<Boolean> response = Response.success(true);
            log.info("活动装配，数据预热，完成 activityId:{}", activityId);
            return response;
        } catch (Exception e) {
            log.error("活动装配，数据预热，失败 activityId:{}", activityId, e);
            return Response.fail();
        }
    }

    /**
     * 执行抽奖
     * @param request 用户id 活动id
     * @return 抽奖结果
     */
    @RateLimiterAccessInterceptor(key = "userId", fallbackMethod = "drawRateLimiterError", permitsPerSecond = 1, blacklistCount = 1)
    @HystrixCommand(commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "150")
    }, fallbackMethod = "drawHystrixError")
    @PostMapping("draw")
    @Override
    public Response<ActivityDrawResponseDTO> draw(@RequestBody ActivityDrawRequestDTO request) {
        try {
            log.info("活动抽奖 userId:{} activityId:{}", request.getUserId(), request.getActivityId());
            // 降级校验
            if ("open".equals(degradeSwitch)) {
                return Response.<ActivityDrawResponseDTO>builder()
                        .code(ResponseCode.DEGRADE_SWITCH.getCode())
                        .info(ResponseCode.DEGRADE_SWITCH.getInfo())
                        .build();
            }
            // 1. 参数校验
            if (StringUtils.isBlank(request.getUserId()) || null == request.getActivityId() ) {
                throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), ResponseCode.ILLEGAL_PARAMETER.getInfo());
            }
            // 2. 参与活动 - 创建参与记录订单
            UserRaffleOrderEntity orderEntity = activityPartakeService.createActivityPartake(ActivityPartakeEntity.builder()
                    .activityId(request.getActivityId())
                    .userId(request.getUserId())
                    .build());
            log.info("活动抽奖，创建订单 userId:{} activityId:{} orderId:{}", request.getUserId(), request.getActivityId(), orderEntity.getOrderId());
            // 3. 抽奖策略 - 执行抽奖
            RaffleAwardEntity raffleAwardEntity = raffleStrategy.performRaffle(RaffleFactorEntity.builder()
                    .userId(orderEntity.getUserId())
                    .strategyId(orderEntity.getStrategyId())
                    .activityEndTime(orderEntity.getActivityEndTime())
                    .build());
            // 4. 存放结果 - 写入中奖记录
            AwardRecordEntity userAwardRecord = AwardRecordEntity.builder()
                    .userId(orderEntity.getUserId())
                    .activityId(orderEntity.getActivityId())
                    .strategyId(orderEntity.getStrategyId())
                    .orderId(orderEntity.getOrderId())
                    .awardId(raffleAwardEntity.getAwardId())
                    .awardTitle(raffleAwardEntity.getAwardTitle())
                    .awardTime(new Date())
                    .awardState(AwardStateVO.create)
                    .awardConfig(raffleAwardEntity.getAwardConfig())
                    .build();
            awardService.createAwardRecord(userAwardRecord);
            // 5. 返回结果
            return Response.success(ActivityDrawResponseDTO.builder()
                    .awardId(raffleAwardEntity.getAwardId())
                    .awardTitle(raffleAwardEntity.getAwardTitle())
                    .awardIndex(raffleAwardEntity.getSort())
                    .build());
        } catch (AppException e) {
            log.warn("活动抽奖失败 userId:{} activityId:{} ", request.getUserId(), request.getActivityId(), e);
            return Response.fail(e);
        } catch (Exception e) {
            log.warn("活动抽奖失败 userId:{} activityId:{}", request.getUserId(), request.getActivityId(), e);
            return Response.fail();
        }
    }

    public Response<ActivityDrawResponseDTO> drawRateLimiterError(@RequestBody ActivityDrawRequestDTO request) {
        log.info("活动抽奖限流 userId:{} activityId:{}", request.getUserId(), request.getActivityId());
        return Response.<ActivityDrawResponseDTO>builder()
                .code(ResponseCode.RATE_LIMITER.getCode())
                .info(ResponseCode.RATE_LIMITER.getInfo())
                .build();
    }

    public Response<ActivityDrawResponseDTO> drawHystrixError(@RequestBody ActivityDrawRequestDTO request) {
        log.info("活动抽奖熔断 userId:{} activityId:{}", request.getUserId(), request.getActivityId());
        return Response.<ActivityDrawResponseDTO>builder()
                .code(ResponseCode.HYSTRIX.getCode())
                .info(ResponseCode.HYSTRIX.getInfo())
                .build();
    }

    /**
     * 签到返利接口
     * @param userId 用户ID
     * @return 签到成功结果
     */
    @PostMapping("signRebate")
    @Override
    public Response<Boolean> calendarSignRebate(@RequestParam String userId) {
        try {
            BehaviorEntity behaviorEntity = new BehaviorEntity();
            behaviorEntity.setUserId(userId);
            behaviorEntity.setBehaviorTypeVO(BehaviorTypeVO.SIGN);
            behaviorEntity.setOutBusinessNo(dateFormatDay.format(new Date()));
            List<String> behaviorRebateOrderIdList = behaviorRebateService.createBehaviorRebateOrder(behaviorEntity);
            log.info("日历签到返利完成 userId:{} orderIds: {}", userId, JSON.toJSONString(behaviorRebateOrderIdList));
            return Response.success(true);
        }catch (AppException e){
            return Response.fail(e);
        } catch (Exception e) {
            return Response.fail();
        }
    }

    /**
     * 签到结果查询
     * @param userId 用户ID
     */
    @GetMapping("isCalendarSignRebate")
    @Override
    public Response<Boolean> isCalendarSignRebate(String userId) {
        try {
            String outBusinessNo = dateFormatDay.format(new Date());
            Boolean calendarSignRebate = behaviorRebateService.isCalendarSignRebate(userId, outBusinessNo);
            return Response.success(calendarSignRebate);
        } catch (Exception e) {
            log.error("查询用户是否完成日历签到返利失败 userId:{}", userId, e);
            return Response.fail(false);
        }
    }

    /**
     * 查询用户账户额度
     * @param request 用户和活动ID
     * @return AccountSurplusResponseDTO 用户账户额度
     */
    @GetMapping("queryAccountSurplus")
    @Override
    public Response<AccountSurplusResponseDTO> queryAccountSurplus(AccountSurplusRequestDTO request) {
        // 1. 参数校验
        if (StringUtils.isBlank(request.getUserId()) || null == request.getActivityId()) {
            throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), ResponseCode.ILLEGAL_PARAMETER.getInfo());
        }
        try {
            ActivityAccountEntity activityAccountEntity = activityPartakeService.queryAccountSurplus(request.getUserId(), request.getActivityId());
            AccountSurplusResponseDTO userActivityAccountResponseDTO = AccountSurplusResponseDTO.builder()
                    .totalCount(activityAccountEntity.getTotalCount())
                    .totalCountSurplus(activityAccountEntity.getTotalCountSurplus())
                    .dayCount(activityAccountEntity.getDayCount())
                    .dayCountSurplus(activityAccountEntity.getDayCountSurplus())
                    .monthCount(activityAccountEntity.getMonthCount())
                    .monthCountSurplus(activityAccountEntity.getMonthCountSurplus())
                    .build();
            log.info("查询用户活动账户完成 userId:{} activityId:{} dto:{}", request.getUserId(), request.getActivityId(), JSON.toJSONString(userActivityAccountResponseDTO));
            return Response.success(userActivityAccountResponseDTO);
        } catch (Exception e) {
            log.error("查询用户活动账户失败 userId:{} activityId:{}", request.getUserId(), request.getActivityId(), e);
            return Response.fail();
        }
    }

    /**
     * 查询用户中奖记录
     *
     * @param request 用户ID
     * @return 中奖记录列表
     */
    @GetMapping("queryAwardRecord")
    @Override
    public PageResult<AwardRecordResponseDTO> queryAwardRecord(AwardRecordRequestDTO request) {
        if (StringUtils.isBlank(request.getUserId()) || null == request.getActivityId()) {
            throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), ResponseCode.ILLEGAL_PARAMETER.getInfo());
        }
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        List<AwardRecordEntity> awardRecordEntityList = awardService.queryAwardRecord(request.getUserId(), request.getActivityId());
        List<AwardRecordResponseDTO> result = new ArrayList<>();
        awardRecordEntityList.forEach(awardRecordEntity -> {
            AwardRecordResponseDTO awardRecordResponseDTO = AwardRecordResponseDTO.builder()
                    .raffleOrderId(awardRecordEntity.getOrderId())
                    .awardId(awardRecordEntity.getAwardId())
                    .awardTitle(awardRecordEntity.getAwardTitle())
                    .awardTime(awardRecordEntity.getAwardTime())
                    .build();
            result.add(awardRecordResponseDTO);
        });
        return PageResult.build(PageInfo.of(result));
    }


    /**
     * 查询活动sku列表
     * @param activityId 活动ID
     * @return List<SkuProductResponseDTO> sku商品集合
     */
    @GetMapping("querySkuProductListByActivityId")
    @Override
    public Response<List<SkuProductResponseDTO>> querySkuProductListByActivityId(Long activityId) {
        try {
            log.info("查询sku商品集合开始 activityId:{}", activityId);
            // 1. 参数校验
            if (null == activityId) {
                throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), ResponseCode.ILLEGAL_PARAMETER.getInfo());
            }
            // 2. 查询商品&封装数据
            List<SkuProductEntity> skuProductEntities = raffleActivitySkuProductService.querySkuProductEntityListByActivityId(activityId);
            List<SkuProductResponseDTO> skuProductResponseDTOS = new ArrayList<>(skuProductEntities.size());
            for (SkuProductEntity skuProductEntity : skuProductEntities) {

                SkuProductResponseDTO.ActivityCount activityCount = new SkuProductResponseDTO.ActivityCount();
                activityCount.setTotalCount(skuProductEntity.getActivityCount().getTotalCount());
                activityCount.setMonthCount(skuProductEntity.getActivityCount().getMonthCount());
                activityCount.setDayCount(skuProductEntity.getActivityCount().getDayCount());

                SkuProductResponseDTO skuProductResponseDTO = new SkuProductResponseDTO();
                skuProductResponseDTO.setSku(skuProductEntity.getSku());
                skuProductResponseDTO.setActivityId(skuProductEntity.getActivityId());
                skuProductResponseDTO.setActivityCountId(skuProductEntity.getActivityCountId());
                skuProductResponseDTO.setStockCount(skuProductEntity.getStockCount());
                skuProductResponseDTO.setStockCountSurplus(skuProductEntity.getStockCountSurplus());
                skuProductResponseDTO.setProductAmount(skuProductEntity.getProductAmount());
                skuProductResponseDTO.setActivityCount(activityCount);
                skuProductResponseDTOS.add(skuProductResponseDTO);
            }
            log.info("查询sku商品集合完成 activityId:{} skuProductResponseDTOS:{}", activityId, JSON.toJSONString(skuProductResponseDTOS));
            return Response.success(skuProductResponseDTOS);
        } catch (Exception e) {
            log.error("查询sku商品集合失败 activityId:{}", activityId, e);
            return Response.fail(e);
        }
    }

    /**
     * 查询用户积分账户可用积分
     * @param userId 用户ID
     * @return 积分账户
     */
    @GetMapping("queryUserCreditAccount")
    @Override
    public Response<BigDecimal> queryUserCreditAccount(String userId) {
        try {
            log.info("查询用户积分值开始 userId:{}", userId);
            CreditAccountEntity creditAccountEntity = creditAdjustService.queryUserCreditAccount(userId);
            log.info("查询用户积分值完成 userId:{} adjustAmount:{}", userId, creditAccountEntity.getAdjustAmount());
            return Response.success(creditAccountEntity.getAvailableAmount());
        } catch (Exception e) {
            log.error("查询用户积分值失败 userId:{}", userId, e);
            return Response.fail(e);
        }
    }

    /**
     * 积分支付兑换商品
     * @param request 请求对象「用户ID、商品ID」
     * @return 积分支付兑换商品结果
     */
    @PostMapping("creditPayExchangeSku")
    @Override
    public Response<Boolean> creditPayExchangeSku(@RequestBody SkuProductShopCartRequestDTO request) {
        try {
            log.info("积分兑换商品开始 userId:{} sku:{}", request.getUserId(), request.getSku());
            // 1. 创建兑换商品sku订单，outBusinessNo 每次创建出一个单号。
            UnpaidActivityOrderEntity unpaidActivityOrder = raffleActivityAccountQuotaService.creatSkuRechargeOrder(SkuRechargeEntity.builder()
                    .userId(request.getUserId())
                    .sku(request.getSku())
                    .bizId(RandomStringUtils.randomNumeric(12))
                    .orderTradeType(OrderTradeTypeVO.credit_pay_trade)
                    .build());
            log.info("积分兑换商品，创建订单完成 userId:{} sku:{} outBusinessNo:{}", request.getUserId(), request.getSku(), unpaidActivityOrder.getOutBusinessNo());

            // 2.支付兑换商品
            String orderId = creditAdjustService.createCreditOrder(TradeEntity.builder()
                    .userId(unpaidActivityOrder.getUserId())
                    .tradeName(TradeNameVO.CONVERT_SKU)
                    .tradeType(TradeTypeVO.REVERSE)
                    .amount(unpaidActivityOrder.getPayAmount().negate())
                    .outBusinessNo(unpaidActivityOrder.getOutBusinessNo())
                    .build());
            log.info("积分兑换商品，支付订单完成  userId:{} sku:{} orderId:{}", request.getUserId(), request.getSku(), orderId);

            return Response.fail(true);
        } catch (Exception e) {
            log.error("积分兑换商品失败 userId:{} sku:{}", request.getUserId(), request.getSku(), e);
            return Response.fail(e);
        }
    }

}
